package club.janna.hello.parser;

//import club.janna.hello.factory.DeviceFactory;
//import club.janna.hello.model.Inverter;
import club.janna.hello.parser.constants.IEC104Statute;
//import club.janna.hello.util.CommonUtil;
import club.janna.hello.util.DataConvertor;
//import club.janna.hello.util.TemplateUtilTest;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by guopanbo on 17/12/28
 */
public class IEC104Parser implements Runnable {

    private byte[] data;
    private ChannelHandlerContext ctx;

    public IEC104Parser(byte[] data, ChannelHandlerContext ctx) {
        this.data = data;
        this.ctx = ctx;
    }

    /**
     * 解析规约
     * @param source 10进制数字数组
     * @return
     */
    private int parse(int[] source) {
        if(source.length < 6 || source.length > 255)
            throw new RuntimeException(String.format("data length[%d] invalid", source.length));
        int offset = 0, value;
        //报文头
        value = source[offset ++];
        if(value != IEC104Statute.HEAD)
            throw new RuntimeException(String.format("data head[%#02x] invalid", value));
        //报文长度
        value = source[offset ++];
        if(value + 2 != source.length)
            throw new RuntimeException(String.format("data length[%#02x] invalid", value));
        //4个控制域
        int[] controlDomains = new int[4];
        System.arraycopy(source, offset, controlDomains, 0, 4);
        offset += 4;
        if((controlDomains[0] & 0x01) == 0) {
            //I格式
            System.out.println("I格式");

            //报文类型
            int type = source[offset ++];
            System.out.printf("报文类型：%d\n", type);

            //可变结构限定词
            value = source[offset ++];
            //元素个数（对0x80取模，相当于按位与0x7F）
            int elementNum = value & 0x7F;
            System.out.printf("有 %d 个元素\n", elementNum);
            //序列号是否是连续的
            boolean continuously = value >> 7 != 0;

            //传送原因
            int reason = DataConvertor.int2Byte2IntFLAH(source[offset ++], source[offset ++]);


            //浮点型遥测
            if(type == IEC104Statute.TYPE_TELEMETRY_FLOAT_DATA) {
                System.out.println("浮点型遥测");

                if(reason == IEC104Statute.REASON_OUTBREAK)
                    //突发
                    System.out.println("传送原因：突发");
                else if(reason == IEC104Statute.REASON_CYCLE)
                    System.out.println("传送原因：循环/周期");
                else
                    System.out.printf("传送原因：%d\n", value);

                //子站地址
                value = source[offset ++];
                System.out.printf("子站地址：%d\n", value);
                //站址
                value = DataConvertor.int2Byte2IntFLAH(source[offset ++], source[offset ++]);
                System.out.printf("站址：%d\n", value);
                Map<Integer, Float> dataMap = new HashMap<>();
                if(continuously) {
                    //元素地址是连续的
                    System.out.println("元素地址是连续的");
                    //元素起始地址
                    int itemAddress = DataConvertor.int3Byte2IntFLAH(source[offset ++], source[offset ++], source[offset ++]);
                    for(int i = 0; i < elementNum; i ++) {
                        //数据，浮点型
                        float itemData = DataConvertor.int4Byte2FloatFLAH(source[offset ++], source[offset ++], source[offset ++], source[offset ++]);
                        //数据质量
                        int itemQuality = source[offset ++];
                        System.out.printf("第 %d 个元素：\n\t元素地址：%d\n\t数据：%f\n\t数据质量：%d\n", i + 1, itemAddress + i, itemData, itemQuality);
                        dataMap.put(itemAddress + i,itemData);
                    }
                } else {
                    //元素地址不是连续的
                    System.out.println("元素地址不是连续的");
                    for(int i = 0; i < elementNum; i ++) {
                        //元素地址
                        int itemAddress = DataConvertor.int3Byte2IntFLAH(source[offset ++], source[offset ++], source[offset ++]);
                        //数据，浮点型
                        float itemData = DataConvertor.int4Byte2FloatFLAH(source[offset ++], source[offset ++], source[offset ++], source[offset ++]);
                        //数据质量
                        int itemQuality = source[offset ++];
                        System.out.printf("第 %d 个元素：\n\t元素地址：%d\n\t数据：%f\n\t数据质量：%d\n", i + 1, itemAddress, itemData, itemQuality);
                        dataMap.put(itemAddress,itemData);
                    }
                }
                //组装数据，入库等操作
//                if(!dataMap.isEmpty()){
//                    System.out.println("转换Map开始：");
//                    Map objectMap = DeviceFactory.parseMap(dataMap, TemplateUtilTest.templateMap);
//                    System.out.println("转换对象开始：");
//                    Inverter inverter = (Inverter)CommonUtil.ConvertMapToObj(objectMap, Inverter.class);
//                    System.out.println("转换对象结束：");
//                }
//                Inverter data = DeviceFactory.generate(dataMap, "16395,16387,16389,,,16388", Inverter.class);
//                System.out.println(data.getAc_a());
                //发送确认应答
                sendData(IEC104Statute.confirmAckData(0, 0));
            } else if(type == IEC104Statute.TYPE_SUMMON_OVERALL) {
                //总召唤
                System.out.println("总召唤");
                if(reason == IEC104Statute.REASON_CONFIRM_ACTIVATING)
                    //确认激活
                    System.out.println("传送原因：激活确认");
                else if(reason == IEC104Statute.REASON_END_ACTIVATION)
                    //激活结束
                    System.out.println("传送原因：激活结束");
            }

        } else {
            if((controlDomains[0] >> 1 & 0x01) == 0) {
                //S格式
                System.out.println("S格式");
            } else {
                //U格式
                System.out.println("U格式");
                //连接确认
                if(controlDomains[0] == IEC104Statute.CON_ACK)
                    //发送总召
                    sendData(IEC104Statute.summonOverall(0, 0));
            }
        }

        return 0;
    }

    /**
     * 发送数据
     * @param data
     */
    private void sendData(byte[] data) {
        if(ctx != null && ctx.channel() != null && ctx.channel().isActive()) {
            //byte[] data = new byte[]{0x68, 0x04, 0x01, 0x00, 0x02, 0x00};
            //byte[] data = "hello ".getBytes();
            //byte[] data = IEC104Statute.TEST_ACK_DATA;
            ctx.writeAndFlush(Unpooled.copiedBuffer(data));
            System.out.println("发送数据：" + DataConvertor.Byte2String(data));
        }
    }

    @Override
    public void run() {
        if(data == null || data.length == 0)
            throw new RuntimeException("data is null");
        int[] decArray = DataConvertor.HexByteArray2DecArray(data);
        System.out.println("服务器接收到的数据：" + DataConvertor.Byte2String(data));
        //System.out.println("线程：" + Thread.currentThread().getName());
        parse(decArray);
    }
}
